package com.example.demo03_form_login.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //配置明文加密方式
    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //开启基于内存定义的用户认证
        auth.inMemoryAuthentication()
                .withUser("wangnian")
                .password("123")
                .roles("admin");
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        //放行静态资源，这样配置相当于不走 spring security 的过滤器
        web.ignoring().antMatchers("/css/**","/js/**","/images/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                //拦截放行之外的所有请求
                .anyRequest().authenticated()
                .and()
                //开启表单认证
                .formLogin()
                //设置登录页面，如果没有设置登录接口，则登录接口与登录页面一致为 /login.html 的 POST 请求
                .loginPage("/login.html")
                //单独设置登录接口
                .loginProcessingUrl("/doLogin")

                //设置 表单提交的用户名和密码的参数名称，
                // 就是设置 FormLoginConfigurer 的 UsernamePasswordAuthenticationFilter 的 usernameParameter 和 passwordParameter（UsernamePasswordAuthenticationFilter 是其父类的一个属性）
                //之后登录接口过来，就会调用 UsernamePasswordAuthenticationFilter#obtainUsername，#obtainPassword 来获取 request 的用户名和密码
                .usernameParameter("name")
                .passwordParameter("pwd")

                 /*successForwardUrl 表示登录成功之后一律跳到 /index.html 页面
                 defaultSuccessUrl 分两种情况，
                      1.输入登录地址，且登录成功后，将跳转到 /index.html；
                      2.输入其它地址，因为没有登录而重定向到登录地址，然后登录成功后会跳转到登录之前输入的地址
                 defaultSuccessUrl(String,boolean) 还有一个重载方法，如果第二个参数为 true，则和 successForwardUrl 规则一样。
                 下面两个只需要配一个就行 */
                //.successForwardUrl("/index.html")
                .defaultSuccessUrl("/index.html")

                // failureForwardUrl 是登录失败之后会发生服务端跳转，failureUrl 则在登录失败之后，会发生重定向。
                // 下面两个只需要配一个就行
//                .failureForwardUrl("/fail")// 利用 failureForwardUrl 配置路径不会被放行(因为是服务端跳转，不需要放行)
                .failureUrl("/fail.html")// 利用 failureUrl 配置路径会被放行
                .permitAll()//放行登录相关操作的请求

                .and()
                .logout()
                //配置注销登录的地址，默认是 /logout GET, logoutSuccessUrl 配置的是也是 GET 请求的地址，
                //logoutRequestMatcher 传入 AntPathRequestMatcher ，接口地址和请求方法都可以配置，下面两个配置一个就行
//                .logoutUrl("/logout666")
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout666","GET"))
                .logoutSuccessUrl("/logoutSuccess.html")//退出成功跳转的页面
                .deleteCookies()//清除 cookie
                .clearAuthentication(true)//清除认证信息，默认
                .invalidateHttpSession(true)//使 HttpSession 失效，默认
                .permitAll()//放行退出登录的相关请求

                .and()
                .csrf().disable();//关闭 csrf
    }
}
